﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once

#include "GcmpCommonEdit.h"
#include "GbmpPickActionBase.h"

namespace gcmp
{
    class Document;
    class IPickFilter;
    class IUiView;
    class ISnapCandidates;
    class ISnapContext;
    class IElementShapeHandle;
    class IPickEventHandler;
    class IActionModifyDoubleClickEventHandler;
    class IActionModifyDoubleClickEvent;
    class IActionModifyBehavior;
    class TestHighlightChangeEventHandler;

    class GbmpActionModify final: public GbmpPickActionBase
    {

    public:
        GbmpActionModify();
        virtual ~GbmpActionModify();

        // IAction接口继承
    public:
        virtual void InitAction(gcmp::IUiView* pCurrentView) override;
        virtual void ActionCancelled() override;

        // 鼠标事件处理
        virtual bool OnRButtonDown(IUiView* pCurrentView, const Vector3d& pos) override;
        virtual bool OnRButtonUp(IUiView* pCurrentView, const Vector3d& pos) override;
        virtual bool OnLButtonDown(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) override;
        virtual bool OnLButtonUp(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) override;
        virtual bool OnLButtonDoubleClick(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) override;
        virtual bool OnMovePoint(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) override;
        
        // 键盘事件处理
        virtual bool OnKeyDown(gcmp::IUiView* pCurrentView, int nChar) override;
        virtual bool OnKeyUp(gcmp::IUiView* pCurrentView, int nChar) override;
        
        // 上下文菜单
        virtual OwnerPtr<IMenuItemContainerDefinition> PrepareContextMenu(gcmp::IUiView* pUIView) override;

        // 视图切换事件处理
        virtual bool PreviewViewSwitched() override { return false; }
        virtual bool OnViewSwitched(gcmp::IUiView* pUIView) override;

    public:
        gcmp::IPickFilter* GetFilterForLocalSnap() { return m_oFilterForLocalSnap.get(); }
        void SetFilterForLocalSnap(OwnerPtr<gcmp::IPickFilter> oFilterForLocalSnap);

        gcmp::IPickFilter* GetFilterForRemoteSnap() { return m_oFilterForRemoteSnap.get(); }
        void SetFilterForRemoteSnap(OwnerPtr<gcmp::IPickFilter> oFilterForRemoteSnap);


        bool AddPickPostProcessEventHandler(OwnerPtr<IPickEventHandler> opEventHandler);
        bool AddRectPickPostProcessEventHandler(OwnerPtr<IPickEventHandler> opEventHandler);

        void SetModifyElementsBehavior(OwnerPtr<IActionModifyBehavior> opModifyBehavior);
        // 重载PickActionBase实现
    protected:
        virtual void OnSelectionChanged() override;

    private:
        void CollectMoveElements(gcmp::IDocument* pDoc);

        void SnapPoint(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos);
        void GetNearestPoint(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& inputPoint, gcmp::Vector3d& nearPoint);
        bool IsCaught() const { return m_isCaught; }

        //针对某些特殊对象(如标高的辅助点)，移动的逻辑会比较复杂，
        //所以由其特定的Action来代替通用的ModifyAction。
        bool HandledByOtherAction(gcmp::IDocument* pDoc, const gcmp::Vector3d& pos);

        bool IsElementAlreadyInSelection(const IGraphicsNodeReference* pGraphicsNodeReference);

        bool IsMoving() const;
        bool OnMovePoint(gcmp::IUiView* pCurrentView);

        //////////////////////////////////////////////////////////////////////////
        // 需要移除功能

        //重置
        void Reset();

        //////////////////////////////////////////////////////////////////////////
        // 需要重构：获取对象的影子对象
        gcmp::IElement* GetShadow(gcmp::IUiView* pCurrentView, const gcmp::IElement* pElement);
        bool ClearShadows();
        //////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////////

    private:
        bool                  m_isCaught; //捕获标记
        gcmp::Vector3d        m_nearStartPt;//所移动Element上离初始点最近的点，用于捕捉时移动对象

        gcmp::Vector3d        m_interPt;
        gcmp::Vector3d        m_endPt;
        gcmp::Vector3d        m_collinearVec;//最近点和定位线之间的向量

        typedef std::map<gcmp::ElementId, gcmp::ElementId> ElementToShadowMap;
        ElementToShadowMap    m_elementShadows;//对象和其影子对象

        std::vector<gcmp::ElementId>        m_moveElementIds;
        gcmp::OwnerPtr<gcmp::ISnapContext>  m_oSnapContext;
        gcmp::OwnerPtr<gcmp::IPickFilter>   m_oFilterForLocalSnap;
        gcmp::OwnerPtr<gcmp::IPickFilter>   m_oFilterForRemoteSnap;
        gcmp::OwnerPtr<gcmp::ISnapCandidates> m_oSnapCandidates;

        std::vector<gcmp::OwnerPtr<gcmp::IPickEventHandler>> m_opPickEventHandlers;             // 点选处理事件;
        std::vector<gcmp::OwnerPtr<gcmp::IPickEventHandler>> m_opRectPickEventHandlers;         // 拉框捕捉处理事件;
        gcmp::OwnerPtr<gcmp::IActionModifyBehavior>          m_opModifyElementsBehavior;
        gcmp::OwnerPtr<TestHighlightChangeEventHandler>      m_opHightlightChangeEventHandler;
    };

}
